﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using ObjectBakery.Tests.TestFactories;
using ObjectBakery.Tests.TestDoubles;
using System.ComponentModel;

using System.Runtime.Serialization;
using System.Xml;
using ObjectBakery.Helpers;
using System.IO;
using System.Diagnostics;
using System.Net.Mail;
using System.Collections;

namespace ObjectBakery.Tests
{
    /// <summary>
    /// Tests for everything..
    /// </summary>
    [TestClass]
    public class Tests
    {
        public Tests()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        /// <summary>
        /// Excersise Xml Serialization
        /// </summary>
        [TestMethod]
        public void CanSerializeToandFromXml()
        {
            Product product1 = new TestProductFactory().Build()[0];

            SerializationHelper serializationHelper = new SerializationHelper();

            //dehydrate instance to xml UTF8 string
            string sProduct1 = Encoding.UTF8.GetString(serializationHelper.XmlSerialize(product1));

            //rehydrate instance from string
            Product product2 = serializationHelper.XmlDeserialize<Product>(sProduct1);

            //assertions

            //test that xml is well formed
            XmlDocument testLoadDoc = new XmlDocument();
            testLoadDoc.LoadXml(sProduct1); //throws exception if not well formed

            //verify data is the same
            Assert.IsTrue(product1.ID.Equals(product2.ID) && product1.Name.Equals(product2.Name));

            //products themselves are not the same instance, but instead deep copies
            Assert.IsFalse(product1.Equals(product2));
        }

        [TestMethod]
        public void CanSerializeToandFromXml2()
        {
            Product product1 = new TestProductFactory().Build()[0];

            SerializationHelper serializationHelper = new SerializationHelper();

            //dehydrate instance to xml UTF8 string
            string sProduct1 = Encoding.UTF8.GetString(serializationHelper.XmlSerialize(product1));

            //rehydrate instance from string
            Product product2 = (Product)serializationHelper.XmlDeserialize(typeof(Product), sProduct1);

            //assertions

            //test that xml is well formed
            XmlDocument testLoadDoc = new XmlDocument();
            testLoadDoc.LoadXml(sProduct1); //throws exception if not well formed

            //verify data is the same
            Assert.IsTrue(product1.ID.Equals(product2.ID) && product1.Name.Equals(product2.Name));

            //products themselves are not the same instance, but instead deep copies
            Assert.IsFalse(product1.Equals(product2));
        }


        [TestMethod]
        public void CanSerializeToFromSoap()
        {
            Asset asset = new TestAssetFactory().Build()[0];

            SerializationHelper serializationHelper = new SerializationHelper();

            byte[] bAssetA = serializationHelper.SoapSerialize(asset);
            string sAssetA64 = Convert.ToBase64String(bAssetA);
            byte[] bAssetA2 = Convert.FromBase64String(sAssetA64);
            Asset assetA2 = serializationHelper.SoapDeserialize<Asset>(bAssetA2);

            //verify 
            Assert.IsTrue(asset.Name.Equals(assetA2.Name) && asset.ID.Equals(assetA2.ID));

        }

        [TestMethod]
        public void CanSerializeToFromSoap2()
        {
            Asset asset = new TestAssetFactory().Build()[0];

            SerializationHelper serializationHelper = new SerializationHelper();

            byte[] bAssetA = serializationHelper.SoapSerialize(asset);
            string sAssetA64 = Convert.ToBase64String(bAssetA);
            byte[] bAssetA2 = Convert.FromBase64String(sAssetA64);
            Asset assetA2 = (Asset)serializationHelper.SoapDeserialize(bAssetA2);

            //verify 
            Assert.IsTrue(asset.Name.Equals(assetA2.Name) && asset.ID.Equals(assetA2.ID));

        }

        [TestMethod]
        public void CanSerializeToFromBinary()
        {
            Asset asset = new TestAssetFactory().Build()[0];

            byte[] bAsset = new SerializationHelper().BinarySerialize(asset);

            //for kicks we can convert to Base64 string and back
            string sAsset64 = Convert.ToBase64String(bAsset);
            byte[] bAsset2 = Convert.FromBase64String(sAsset64);

            Asset asset2 = new SerializationHelper().BinaryDeserialize<Asset>(bAsset2);

            //verify 
            Assert.IsTrue(asset.Name.Equals(asset2.Name) && asset.ID.Equals(asset2.ID));
            Assert.IsFalse(asset.Equals(asset2)); //deep copy
        }

        [TestMethod]
        public void CanSerializeToFromBinary2()
        {
            Asset asset = new TestAssetFactory().Build()[0];

            byte[] bAsset = new SerializationHelper().BinarySerialize(asset);

            //for kicks we can convert to Base64 string and back
            string sAsset64 = Convert.ToBase64String(bAsset);
            byte[] bAsset2 = Convert.FromBase64String(sAsset64);

            Asset asset2 = (Asset)new SerializationHelper().BinaryDeserialize(bAsset2);

            //verify 
            Assert.IsTrue(asset.Name.Equals(asset2.Name) && asset.ID.Equals(asset2.ID));
            Assert.IsFalse(asset.Equals(asset2)); //deep copy
        }

        [TestMethod]
        public void CanDataContractSerializeDeserialize()
        {
            Product product = new TestProductFactory().Build()[0];
            var serializationHelper = new SerializationHelper();

            var pBytes = serializationHelper.DataConractSerialize(product);
            string xstring = Encoding.UTF8.GetString(pBytes);

            var pBytes2 = Encoding.UTF8.GetBytes(xstring);
            Product product2 = serializationHelper.DataConractDeserialize<Product>(pBytes2);

            //verify 
            Assert.IsTrue(product.Name.Equals(product2.Name) && product.ID.Equals(product2.ID));
            Assert.IsFalse(product.Equals(product2)); //deep copy
        }


        [TestMethod]
        public void CanDataContractSerializeDeserialize2()
        {
            Product product = new TestProductFactory().Build()[0];
            var serializationHelper = new SerializationHelper();

            var pBytes = serializationHelper.DataConractSerialize(product);
            string xstring = Encoding.UTF8.GetString(pBytes);

            var pBytes2 = Encoding.UTF8.GetBytes(xstring);
            Product product2 = (Product)serializationHelper.DataConractDeserialize(typeof(Product), pBytes2);

            //verify 
            Assert.IsTrue(product.Name.Equals(product2.Name) && product.ID.Equals(product2.ID));
            Assert.IsFalse(product.Equals(product2)); //deep copy
        }

        [TestMethod]
        public void CanJsonSerializeDeserialize()
        {
            Product product = new TestProductFactory().Build()[0];
            var serializationHelper = new SerializationHelper();

            string xstring = serializationHelper.JsonSerialize(product);
          

            Product product2 = serializationHelper.JsonDeserialize<Product>(xstring);

            //verify 
            Assert.IsTrue(product.Name.Equals(product2.Name) && product.ID.Equals(product2.ID));
            Assert.IsFalse(product.Equals(product2)); //deep copy
        }

        [TestMethod]
        public void CanJsonSerializeDeserialize2()
        {

            //see list cast failing.. investigate identify, walk, and cast to build typed list from object[]

            Product product = new TestProductFactory().Build()[0];
            var serializationHelper = new SerializationHelper();

            string xstring = serializationHelper.JsonSerialize(product);

            IDictionary dict = (IDictionary)serializationHelper.JsonDeserialize(xstring);

            Product product2 = new Product();

            new DataSyncHelper().Sync(dict, product2);


            //verify 
            Assert.IsTrue(product.Name.Equals(product2.Name) && product.ID.Equals(product2.ID));
            Assert.IsFalse(product.Equals(product2)); //deep copy
        }


        [TestMethod]
        public void CanJsonSerializeDeserialize3()
        {
            Asset asset = new TestAssetFactory().Build()[0];
            var serializationHelper = new SerializationHelper();

            string xstring = serializationHelper.JsonSerialize(asset);

            IDictionary dict = (IDictionary)serializationHelper.JsonDeserialize(xstring);

            Asset asset2 = new Asset();

            new DataSyncHelper().Sync(dict, asset2);


            //verify 
            Assert.IsTrue(asset.Name.Equals(asset2.Name) && asset.ID.Equals(asset2.ID));
            Assert.IsFalse(asset.Equals(asset2)); //deep copy
        }


        [TestMethod]
        public void CanGetMemoryStreamFromEmbeddedResource()
        {
            MemoryStream ms = AssemblyHelper.GetResourceAsMemoryStream(
                                 this.GetType().Assembly, "TestAssets.1220080919a.jpg");

            Assert.IsTrue(ms.ToArray().Length > 0);
        }

        [TestMethod]
        public void CanMoveFileDataBetweenFormatsWithFullExcersise()
        {
            DateTime start = DateTime.Now;
            Debug.WriteLine(start.ToString());

            Product product1 = new TestProductFactory().Build()[0];

            SerializationHelper serializationHelper = new SerializationHelper();

            //dehydrate instance to xml UTF8 string
            string sProduct1 = Encoding.UTF8.GetString(serializationHelper.XmlSerialize(product1));

            byte[] testBytes1 = Encoding.UTF8.GetBytes(sProduct1);

            string testBase64 = Convert.ToBase64String(testBytes1);

            byte[] testBytes2 = Convert.FromBase64String(testBase64);

            #region trip strategies

            ////round trip to file and back
            FileInfo tempFile = new FileSystemHelper().GetTempFile();
            File.WriteAllBytes(tempFile.FullName, testBytes2);
            byte[] testBytes3 = File.ReadAllBytes(tempFile.FullName);
            tempFile.Delete();

            //round trip through email and back

            //round trip to database and back

            //round trip through web request/response

            //ftp trip to and from

            //round trip through message queue

            #endregion



            string sProduct2 = Encoding.UTF8.GetString(testBytes3);

            //rehydrate instance from string
            Product product2 = serializationHelper.XmlDeserialize<Product>(sProduct2);

            ObjectDumper.Write(product2);

            var diCache = new FileSystemHelper().GetEnsuredDirectory(@".\cache");
            product2.Assets.ForEach(asset =>
            {
                string path = diCache.FullName + @"\" + asset.Name + '.' + asset.Format;
                File.WriteAllBytes(path, asset.Data);
            });

            DateTime end = DateTime.Now;
            Debug.WriteLine(end.ToString());
            Debug.WriteLine("Completed in: " + (end - start).Milliseconds.ToString() + " Milliseconds");

            //assertions

            //xml is well formed
            XmlDocument testLoadDoc = new XmlDocument();
            testLoadDoc.LoadXml(sProduct2);

            //string versions of products should equate
            Assert.IsTrue(sProduct1.Equals(sProduct2));

            //id verification
            Assert.IsTrue(product1.ID.Equals(product2.ID));

            //products themselves are not the same instance
            Assert.IsFalse(product1.Equals(product2));
        }


    }
}
